package org.alvin.gencode.swaggerapidoc;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.alvin.gencode.beans.PropConfig;
import org.alvin.gencode.swagger.bean.ActionBean;
import org.alvin.gencode.swagger.bean.ActionMethodBean;
import org.alvin.gencode.swagger.service.HttpClientService;
import org.alvin.gencode.utils.ConfigUtil;
import org.alvin.gencode.utils.VelocityUtil;
import org.alvin.mini_inject.annotations.MiniComponent;
import org.alvin.mini_inject.annotations.MiniInject;
import org.apache.velocity.app.VelocityEngine;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@MiniComponent
public class SwaggerApiDocService {

    @MiniInject
    private HttpClientService httpClientService;


    public void genDoc(PropConfig propConfig) throws Exception {
        log.info("启动配置加载");
        Path path = Paths.get(propConfig.getConfigDir(), "swagger.rmb");
        List<String> list = Lists.newArrayList();
        if (Files.exists(path)) {
            try {
                list = Files.readAllLines(path);
                log.info("递增执行,过滤掉api 列表:" + list);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.genDoc(propConfig, propConfig.getSwaggerUrl(), propConfig.getSwaggerApiType(), list);
    }

    public void genDoc(PropConfig propConfig, String url, String type, List<String> tags) throws Exception {
        String html = httpClientService.get(url);
        html = html.replaceAll("[$]ref", "_ref");
        JSONObject jsonObject = JSONObject.parseObject(html);
        JSONArray jsonArray = jsonObject.getJSONArray("tags");

        List<ActionBean> actionBeans = Lists.newArrayList();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject tag = jsonArray.getJSONObject(i);
            if (tags.contains(tag.getString("name"))) {
                continue;
            }
            tags.add(tag.getString("name"));
            ActionBean actionBean = new ActionBean();
            actionBean.setAuthor(propConfig.getAuthor());
            actionBean.setDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            actionBean.setActionName(tag.getString("name"));
            actionBean.setNote(tag.getString("description"));
            actionBean.setMethods(createActionMethods(actionBean, jsonObject.getJSONObject("paths"), jsonObject.getJSONObject("definitions")));
            //
            System.out.println(actionBean);
            actionBeans.add(actionBean);
        }
        this.readerTemplate(propConfig, actionBeans);
    }

    private void readerTemplate(PropConfig propConfig, List<ActionBean> actionBeans) throws Exception {

        //需要循环的变量配置
        HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
        Configure config = Configure.newBuilder()
                .bind("actions", policy)
                .bind("methods", policy)
                .build();
        //组装对象
        List<JSONObject> actionsJson = actionBeans.stream().map(item -> {
            JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(item));
            System.out.println(jsonObject);
            return jsonObject;
        }).collect(Collectors.toList());
        //渲染模板
        XWPFTemplate template = XWPFTemplate.compile(this.getClass().getResourceAsStream("/templates/wxapi.docx"), config).render(
                new HashMap<String, Object>() {{
                    put("title", "小程序Api说明");
                    put("actions", actionsJson);
                    put("date", new SimpleDateFormat("yyyy-MM-DD HH:mm:ss").format(new Date()));
                    put("author", propConfig.getAuthor());
                }}
        );
        //输出
        String outDir = propConfig.getConfigDir().concat(File.separator).concat("dist");
        File dir = new File(outDir);
        dir.mkdirs();

        File file = new File(dir, "SwaggerApi说明文档.docx");
        if (file.exists() && file.isFile()) {
            file.delete();
        }
        FileOutputStream out = new FileOutputStream(file);
        template.write(out);
        out.flush();
        out.close();
        template.close();
    }

    /**
     * 根据tag 拼装 method
     *
     * @param actionBean
     * @param paths
     * @return
     */
    private List<ActionMethodBean> createActionMethods(ActionBean actionBean, JSONObject paths, JSONObject definitions) {
        List<ActionMethodBean> methods = Lists.newArrayList();
        for (Map.Entry<String, Object> pathEntry : paths.entrySet()) {
            if (pathEntry.getKey().equals("/")) {
                continue;
            }
            JSONObject pathJson = (JSONObject) pathEntry.getValue();

            String url = pathEntry.getKey();
            for (String mk : pathJson.keySet()) {
                JSONObject method = pathJson.getJSONObject(mk);
                if (!method.getJSONArray("tags").contains(actionBean.getActionName())) {
                    continue;
                }
                methods.add(createMethod(mk, method, url, definitions));
            }

        }
        return methods;
    }

    /**
     * 构建方法
     *
     * @param method
     * @return
     */
    private ActionMethodBean createMethod(String mk, JSONObject method, String url, JSONObject definitions) {
        ActionMethodBean methodBean = new ActionMethodBean();
        methodBean.setName(url.substring(url.lastIndexOf("/") + 1));
        methodBean.setNote(method.getString("summary"));
        methodBean.setMethod(mk);
        methodBean.setDescription(method.getString("description"));
        methodBean.setConsumes(method.getJSONArray("consumes").getString(0));
        JSONArray jsonArray = method.getJSONArray("parameters");
        if (jsonArray == null) {
            return methodBean;
        }
        methodBean.setParams(new JSONObject());
        List<String> pathParams = Lists.newArrayList();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject param = jsonArray.getJSONObject(i);
            if (param.getString("in").equals("header")) {
                continue;
            }
            if (param.getString("in").equals("body")) {
                methodBean.setReqParamType("body");
                methodBean.setReqParamType("body");
                methodBean.setContentType("application/json");
                JSONObject obj = parseBodyParams(param, definitions);
                if (obj != null) {
                    methodBean.setParams(obj);
                }
                System.out.println(obj);
                continue;
            }
            if (param.getString("in").equals("query")) {
                methodBean.setReqParamType("formdata");
                methodBean.setContentType("application/x-www-form-urlencoded");
                String name = param.getString("name");
                methodBean.getParams().put(name, "类型："+param.getString("type") +" " + param.getString("description"));
                continue;
            }
            if (param.getString("in").equals("path")) {
                //处理path 参数 的方法名
                methodBean.setName(getPathMethodName(url));
                pathParams.add(param.getString("name"));
                methodBean.setHasPath(true);
                String name = param.getString("name");
                methodBean.getParams().put(name, "类型："+param.getString("type") +" " + param.getString("description"));
            }
        }
        //处理path 参数
        if (methodBean.isHasPath()) {
            int index = url.indexOf("/{");
            String tmpUrl = url.substring(0, index);
            if (!pathParams.isEmpty()) {
                tmpUrl += "";
            }
            for (String path : pathParams) {
                tmpUrl += "/" + path;
            }
            methodBean.setUrl(tmpUrl);
            methodBean.setPathParams(pathParams.stream().collect(Collectors.joining(",")));
            if (!methodBean.getPathParams().isEmpty()) {
                methodBean.setPathParams(methodBean.getPathParams() + ",");
            }
        } else {
            methodBean.setUrl(url);
            methodBean.setPathParams("");
        }
        return methodBean;
    }

    private JSONObject parseBodyParams(JSONObject param, JSONObject definitions) {
        JSONObject ref = param.getJSONObject("schema");
        if (ref.get("_ref") != null) {
            String text = ref.getString("_ref");
            int index = text.lastIndexOf("/");
            text = text.substring(index + 1);

            JSONObject jsonObject = definitions.getJSONObject(text);
            return jsonObject;
        }
        return null;
    }

    /**
     * path 请求获取方法
     *
     * @param url
     * @return
     */
    public String getPathMethodName(String url) {
        String regex = "/([^/]+)/\\{";
        Pattern pattern = Pattern.compile(regex);
        Matcher me = pattern.matcher(url);
        if (me.find()) {
            return me.group(1);
        }
        return url;
    }

}
